﻿//  Copyright 2015 Google Inc. All Rights Reserved.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

using NDesk.Options;
using NtCoreLib;
using NtCoreLib.Native.SafeHandles;
using System;
using System.IO;
using System.Windows.Forms;

namespace EditSection;

static class Program
{
    static string GetName(NtSection section, NtMappedSection map)
    {
        string name = string.Empty;
        try
        {
            name = map.FullPath;
            if (string.IsNullOrEmpty(name))
            {
                name = section.FullPath;
            }
        }
        catch (NtException)
        {
        }

        return string.IsNullOrEmpty(name) ? 
                $"Handle {section.Handle.DangerousGetHandle()} - 0x{map.DangerousGetHandle().ToInt64():X}" : name;
    }

    static void ViewSection(NtSection section, bool read_only)
    {
        read_only = read_only || !section.IsAccessGranted(SectionAccessRights.MapWrite);
        using var map = read_only ? section.MapRead() : section.MapReadWrite();
        using SectionEditorForm frm = new(map, GetName(section, map), read_only);
        Application.Run(frm);
    }

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        NtToken.EnableDebugPrivilege();

        try
        {
            if (args.Length == 0)
            {
                Application.Run(new MainForm());
            }
            else
            {
                int handle = -1;
                string text = string.Empty;
                bool read_only = false;
                bool delete_file = false;
                string filename = string.Empty;
                string path = string.Empty;

                OptionSet opts = new() {
                    { "handle=", "Specify an inherited handle to view.",
                        v => handle = int.Parse(v) },
                    { "readonly", "Specify view section readonly", v => read_only = v != null },
                    { "file=", "Specify a file to view", v => filename = v },
                    { "delete", "Delete file after viewing", v => delete_file = v != null },
                    { "path=", "Specify an object manager path to view", v => path = v },
                };

                opts.Parse(args);

                if (handle > 0)
                {
                    using var section = NtSection.FromHandle(new SafeKernelObjectHandle(new IntPtr(handle), true));
                    ViewSection(section, read_only);
                }
                else if (File.Exists(filename))
                {
                    try
                    {
                        using var file = NtFile.Open(NtFileUtils.DosFileNameToNt(filename), null,
                            FileAccessRights.ReadData, FileShareMode.Read | FileShareMode.Delete, FileOpenOptions.NonDirectoryFile);
                        using NtSection section = NtSection.CreateReadOnlyDataSection(file);
                        using var map = section.MapRead();
                        using SectionEditorForm frm = new(map, filename, true, file.Length);
                        Application.Run(frm);
                    }
                    finally
                    {
                        if (delete_file)
                        {
                            File.Delete(filename);
                        }
                    }
                }
                else if (path.Length > 0)
                {
                    using var section = NtSection.Open(path, null, SectionAccessRights.MaximumAllowed);
                    ViewSection(section, read_only);
                }
                else
                {
                    throw new Exception("Invalid command line arguments");
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}
